#!/bin/bash
#------------------------------------------------------------------------------
# =========                 |
# \\      /  F ield         | OpenFOAM: The Open Source CFD Toolbox
#  \\    /   O peration     |
#   \\  /    A nd           | www.openfoam.com
#    \\/     M anipulation  |
#------------------------------------------------------------------------------
#     Copyright (C) 2019-2020 OpenCFD Ltd.
#------------------------------------------------------------------------------
# License
#     This file is part of OpenFOAM, distributed under GPL-3.0-or-later.
#
# Script
#     openfoam [options] [args]
#
# Description
#     Open an interactive bash session with an OpenFOAM environment,
#     or run an OpenFOAM application (with arguments) after first sourcing
#     the OpenFOAM etc/bashrc file from the project directory.
#
# Note
#     This script normally exists in the $WM_PROJECT_DIR/etc/ directory.
#     Do not copy/move/link to other locations. Use instead an edited copy of
#     `bin/tools/openfoam.in` with a hard-coded projectDir entry.
#
#     See OpenFOAM etc/bashrc for (command-line) preferences.
#     Some equivalent settings:
#       -sp     | -DWM_PRECISION_OPTION=SP
#       -dp     | -DWM_PRECISION_OPTION=DP
#       -int32  | -DWM_LABEL_SIZE=32
#       -int64  | -DWM_LABEL_SIZE=64
#
#     However, the '-D' options grant more flexibility. For example,
#         etc/openfoam -DWM_COMPILER=Clang
#
# SeeAlso
#     META-INFO/README.md for other routines that also use META-INFO.
#
#------------------------------------------------------------------------------
# Auto-detect from location. Do not call from within the etc/directory itself!
projectDir="$(\cd "$(dirname "${0%/*}")" && \pwd -L)"

#------------------------------------------------------------------------------
printHelp() {
    cat<<USAGE

Usage: ${0##*/} [OPTION] [application ...]

options:
  -c command            Execute shell commands with OpenFOAM environment
  -Dkey[=value]         Define key/value to pass as a preference
  -sp                   Single precision
  -dp                   Double precision
  -spdp                 Mixed single/double precision
  -int32 | -int64       The label-size
  -etc=DIR              Additional project etc/ directory
  -prefix=DIR           Alternative OpenFOAM project directory
  -show-api | -version  Print META-INFO api value and exit
  -show-patch           Print META-INFO patch value and exit
  -show-prefix          Print project directory and exit
  -test-tutorial        Forward arguments to tutorials/AutoTest
  -init=FILE            Alternative initialization file (expert option)
  -verbose              Set FOAM_VERBOSE=true (interactive only)
  -help                 Print the usage

Open an interactive bash session with an OpenFOAM environment,
or run an OpenFOAM application (with arguments) after first sourcing
the OpenFOAM etc/bashrc file from the project directory:
(${projectDir:-???})

For a persistent OpenFOAM environment, the following can be added to your
~/.bashrc file:

    source ${projectDir:-???}/etc/bashrc

For more information: www.openfoam.com

USAGE
    exit 0 # A clean exit
}


#-------------------------------------------------------------------------------

# Get a value from META-INFO/api-info
# $1 : keyword
getApiInfo()
{
    value="$(sed -ne 's@^'"$1"' *= *\([0-9][0-9]*\).*@\1@p' "$projectDir"/META-INFO/api-info 2>/dev/null)"

    if [ -n "$value" ]
    then
        echo "$value"
    else
        echo "Could not determine OPENFOAM '$1' value" 1>&2
        return 1
    fi
}

#-------------------------------------------------------------------------------

# - No inheritance of FOAM_SETTINGS
# - No default verbosity (only as command-line option)
unset FOAM_CONFIG_ETC FOAM_SETTINGS FOAM_VERBOSE
unset _foamEtcDir _foamSettings _foamScriptCommand _foamSourceBashEnv
unset optTestTut

# Parse options
while [ "$#" -gt 0 ]
do
    case "$1" in
    -h | -help* | --help*)
        printHelp
        ;;
    -show-api | -version | --version)  # Show API and exit
        getApiInfo api
        exit $?
        ;;
    -show-patch)  # Show patch level and exit
        getApiInfo patch
        exit $?
        ;;
    -show-prefix)  # Show project directory and exit
        echo "$projectDir"
        exit $?
        ;;

    -test-tutorial)  # Run tutorials/AutoTest
        optTestTut=true
        ;;

    -c)  # Shell command
        _foamScriptCommand="$2"
        [ -n "$_foamScriptCommand" ] || {
            echo "$0: missing or bad command argument: $2" 1>&2
            exit 1
        }
        shift 2
        break
        ;;

    -D*)  # Define key/value to pass as preference
        setting="${1#-D}"
        if [ -n "$setting" ]
        then
            _foamSettings="$_foamSettings${_foamSettings:+ }$setting"
        fi
        ;;

    -sp | -dp | -spdp)
        # WM_PRECISION_OPTION=(SP|DP|SPDP)
        setting=$(echo "${1#-}" | sed -e 's/-//g;y/sdp/SDP/')
        _foamSettings="$_foamSettings${_foamSettings:+ }WM_PRECISION_OPTION=$setting"
        ;;

    -int32 | -int64)
        # WM_LABEL_SIZE=...
        _foamSettings="$_foamSettings${_foamSettings:+ }WM_LABEL_SIZE=${1#-int}"
        ;;

    -etc=*)
        # Define FOAM_CONFIG_ETC for finding files
        _foamEtcDir="${1#*=}"
        ;;

    -prefix=*)
        projectDir="${1#*=}"
        ;;

    -init=*)
        _foamSourceBashEnv="${1#*=}"
        ;;

    -verbose)
        export FOAM_VERBOSE=true
        ;;

    --)
        shift
        break
        ;;
    -*)
        echo "$0: unknown option: '$1'" 1>&2
        exit 1
        ;;
    *)
        break
        ;;
    esac
    shift
done

#-------------------------------------------------------------------------------

# Sanity check (installed under /bin, /usr/bin, /usr/local/bin)
# This should not happen.
# If copied to a system dir, should also be using hard-coded values!

if [ "${projectDir%/bin}" != "$projectDir" ]
then
    echo "Warning: suspicious project dir: $projectDir" 1>&2
fi

[ -d "$projectDir/META-INFO" ] || {
    echo "Warning: missing META-INFO in OpenFOAM directory:" 1>&2
    echo "    $projectDir" 1>&2
}


# Remove current OpenFOAM environment
if [ -d "$WM_PROJECT_DIR" ] && [ -f "$WM_PROJECT_DIR/etc/config.sh/unset" ]
then
    . "$WM_PROJECT_DIR/etc/config.sh/unset" || true
fi


unset interactive

if [ "$#" -eq 0 ] && [ -z "$_foamScriptCommand" ] && [ -z "$optTestTut" ]
then
    interactive=true
fi

if [ -z "$_foamSourceBashEnv" ]
then
    if [ -n "$interactive" ]
    then
        # Interactive shell, chain off via a file
        _foamSourceBashEnv="$projectDir/bin/tools/source-bashrc"
    else
        # Default: OPENFOAM etc/bashrc
        _foamSourceBashEnv="$projectDir/etc/bashrc"
    fi
fi


[ -f "$_foamSourceBashEnv" ] || {
    echo "Error: file not found: $_foamSourceBashEnv" 1>&2
    exit 2
}

if [ -n "$_foamEtcDir" ] && [ -d "$_foamEtcDir" ]
then
    # Additional etc directory
    export FOAM_CONFIG_ETC="$_foamEtcDir"
fi

if [ -n "$interactive" ]
then
    # Interactive shell
    # -----------------

    # Source ~/.bashrc and OpenFOAM etc/bashrc in one of two ways:
    #   1) Generate and use a tmp file
    #   2) Chain off to a dedicated file  [This is what we use]

    if [ -n "$_foamSettings" ]
    then
        # Pass preferences via the FOAM_SETTINGS mechanism
        export FOAM_SETTINGS="$_foamSettings"
    fi

    ## echo "Source with $_foamSourceBashEnv with '$FOAM_SETTINGS'" 1>&2

    # Newer bash can use --init-file instead of --rcfile
    exec bash --rcfile "$_foamSourceBashEnv" -i
    exit $? # Safety
fi


# Non-interactive shell
# ---------------------

# Source bashrc within a function to preserve command-line arguments
# Suppresses aliases as a side-effect, but non-interactive anyhow.
sourceBashrc()
{
    . "$_foamSourceBashEnv" $_foamSettings
}


if [ -n "$_foamScriptCommand" ]
then
    # A shell command

    sourceBashrc
    exec bash -c "$_foamScriptCommand" "$@"
    exit $? # Safety
fi


if [ -n "$optTestTut" ]
then

    sourceBashrc
    exec "$WM_PROJECT_DIR/tutorials/AutoTest" "$@"
    exit $? # Safety
fi


# An application or a shell script

# It may actually be a script with a '#!/project-path/bin/openfoam',
# so we need to catch this to avoid infinite recursion.
if [ -f "$1" ] \
&& [ -n "$(sed -ne '1{/^#!.*\/openfoam$/p; q}' "$1" 2>/dev/null)" ]
then
    # A shell script

    sourceBashrc
    exec bash "$@"

else
    # An application

    sourceBashrc
    exec "$@"

fi

#------------------------------------------------------------------------------
